import { Byte } from '../../api/io/Byte';
import { HashMap } from '../../api/struct/HashMap';
import { ITimer } from '../../api/timer/ITimer';
import { IAsync } from '../../api/event/IAsync';
import { MathUtils } from '../../api/math/MathUtils';



/**装备信息属性枚举*/
export const enum E_Equip {
	/**装备id*/
	EQUIP_ID = 0,
	/**配置id*/
	CONFIG_ID = 1,
	/**品质*/
	QUALITY = 2,
	/**等级*/
	LEVEL = 3,
	/**强化*/
	STRENG = 4,
	/**主属性*/
	MAIN_ATTRIBUTE = 5,
	/**随机属性*/
	RANDOM_ATTRIBUTE = 6,
	/**基础属性*/
	BASE_ATTRIBUTE = 7,
	/**枚举数量*/
	EnumCount = 8
}


/**装备信息*/
export class Equip {
	/**事件ID*/
	public static readonly EVENT_ID = 'STRUCT_DATA_EQUIP_EVENT_ID';
	/**整体更新事件ID（部分只需要监听整体变化）*/
	public static readonly TOTAL_EVENT_ID = 'STRUCT_DATA_EQUIP_TOTAL_EVENT_ID';
	/**缓存池*/
	private static POOL: Equip[] = [];

	/**创建入口*/
	public static create(json?: string): Equip {
		const c = this.POOL.pop() || new Equip();
		c._destroyed = false;
		c.resetProperty();
		if (json) {
			c.parse(json);
		}
		return c;
	}


	/**已释放*/
	protected _destroyed = false;
	/**装备id (uint32)*/
	protected _equipId: number;
	/**配置id (uint32)*/
	protected _configId: number;
	/**品质 (uint8)*/
	protected _quality: number;
	/**等级 (uint16)*/
	protected _level: number;
	/**强化 (uint16)*/
	protected _streng: number;
	/**主属性 (uint8, int32)*/
	protected _mainAttribute: HashMap<number, number> = null;
	/**随机属性 (uint8, int32)*/
	protected _randomAttribute: HashMap<number, number> = null;
	/**基础属性 (uint8, int32)*/
	protected _baseAttribute: HashMap<number, number> = null;


	/**构建函数-私有，防止外部创建*/
	private constructor() {
	}


	/**释放*/
	public destroy(): void {
		if (this._destroyed) {
			return;
		}
		this._destroyed = true;
		this.resetProperty(true);
		if (Equip.POOL.indexOf(this) === -1) {
			Equip.POOL.push(this);
		}
	}

	/**装备id*/
	public get equipId() {
		return this._equipId;
	}


	/**装备id*/
	public set equipId(v: number) {
		this._equipId = v;
	}


	/**配置id*/
	public get configId() {
		return this._configId;
	}


	/**配置id*/
	public set configId(v: number) {
		this._configId = v;
	}


	/**品质*/
	public get quality() {
		return this._quality;
	}


	/**品质*/
	public set quality(v: number) {
		this._quality = v;
	}


	/**等级*/
	public get level() {
		return this._level;
	}


	/**等级*/
	public set level(v: number) {
		this._level = v;
	}


	/**强化*/
	public get streng() {
		return this._streng;
	}


	/**强化*/
	public set streng(v: number) {
		this._streng = v;
	}


	/**设置主属性*/
	public putMainAttribute(k: number, v: number): number {
		const ov = this._mainAttribute.put(k, v);
		return ov || 0;
	}


	/**获取主属性*/
	public getMainAttribute(k: number) {
		return this._mainAttribute.get(k) || 0;
	}


	/**删除主属性*/
	public removeMainAttribute(k: number): number {
		const ov = this._mainAttribute.remove(k);
		return ov || 0;
	}


	/**获取主属性映射表-键值(外部改变将导致出错，只能用于遍历)*/
	public getMainAttributeKeys(): number[] {
		return this._mainAttribute.getKeys();
	}


	/**获取主属性映射表-值(外部改变将导致出错，只能用于遍历)*/
	public getMainAttributeValues(): number[] {
		return this._mainAttribute.getValues();
	}


	/**清空主属性映射表*/
	public clearMainAttributeMap(): void {
		this._mainAttribute.clear();
	}


	/**设置随机属性*/
	public putRandomAttribute(k: number, v: number): number {
		const ov = this._randomAttribute.put(k, v);
		return ov || 0;
	}


	/**获取随机属性*/
	public getRandomAttribute(k: number) {
		return this._randomAttribute.get(k) || 0;
	}


	/**删除随机属性*/
	public removeRandomAttribute(k: number): number {
		const ov = this._randomAttribute.remove(k);
		return ov || 0;
	}


	/**获取随机属性映射表-键值(外部改变将导致出错，只能用于遍历)*/
	public getRandomAttributeKeys(): number[] {
		return this._randomAttribute.getKeys();
	}


	/**获取随机属性映射表-值(外部改变将导致出错，只能用于遍历)*/
	public getRandomAttributeValues(): number[] {
		return this._randomAttribute.getValues();
	}


	/**清空随机属性映射表*/
	public clearRandomAttributeMap(): void {
		this._randomAttribute.clear();
	}


	/**设置基础属性*/
	public putBaseAttribute(k: number, v: number): number {
		const ov = this._baseAttribute.put(k, v);
		return ov || 0;
	}


	/**获取基础属性*/
	public getBaseAttribute(k: number) {
		return this._baseAttribute.get(k) || 0;
	}


	/**删除基础属性*/
	public removeBaseAttribute(k: number): number {
		const ov = this._baseAttribute.remove(k);
		return ov || 0;
	}


	/**获取基础属性映射表-键值(外部改变将导致出错，只能用于遍历)*/
	public getBaseAttributeKeys(): number[] {
		return this._baseAttribute.getKeys();
	}


	/**获取基础属性映射表-值(外部改变将导致出错，只能用于遍历)*/
	public getBaseAttributeValues(): number[] {
		return this._baseAttribute.getValues();
	}


	/**清空基础属性映射表*/
	public clearBaseAttributeMap(): void {
		this._baseAttribute.clear();
	}



	/**通过枚举获取值*/
	public getV(k: E_Equip): any {
		switch (k) {
			case E_Equip.EQUIP_ID: return this._equipId;
			case E_Equip.CONFIG_ID: return this._configId;
			case E_Equip.QUALITY: return this._quality;
			case E_Equip.LEVEL: return this._level;
			case E_Equip.STRENG: return this._streng;
			case E_Equip.MAIN_ATTRIBUTE: return this._mainAttribute;
			case E_Equip.RANDOM_ATTRIBUTE: return this._randomAttribute;
			case E_Equip.BASE_ATTRIBUTE: return this._baseAttribute;
			default: return null;
		}
	}


	/**通过枚举设置值*/
	public setV(k: E_Equip, v: any): void {
		switch (k) {
			case E_Equip.EQUIP_ID: this._equipId = v; break;
			case E_Equip.CONFIG_ID: this._configId = v; break;
			case E_Equip.QUALITY: this._quality = v; break;
			case E_Equip.LEVEL: this._level = v; break;
			case E_Equip.STRENG: this._streng = v; break;
			case E_Equip.MAIN_ATTRIBUTE: this._mainAttribute = v; break;
			case E_Equip.RANDOM_ATTRIBUTE: this._randomAttribute = v; break;
			case E_Equip.BASE_ATTRIBUTE: this._baseAttribute = v; break;
			default: break;
		}
	}


	/**初始化*/
	public resetProperty(fromDestroy = false): void {
		//装备id
		this._equipId = 0;
		//配置id
		this._configId = 0;
		//品质
		this._quality = 0;
		//等级
		this._level = 0;
		//强化
		this._streng = 0;
		//主属性
		if (this._mainAttribute) {
			this._mainAttribute.clear();
		}
		else {
			this._mainAttribute = new HashMap<number, number>();
		}
		//随机属性
		if (this._randomAttribute) {
			this._randomAttribute.clear();
		}
		else {
			this._randomAttribute = new HashMap<number, number>();
		}
		//基础属性
		if (this._baseAttribute) {
			this._baseAttribute.clear();
		}
		else {
			this._baseAttribute = new HashMap<number, number>();
		}
	}


	/**序列化*/
	public stringify(toString: boolean): string | any {
		const json: any = {};
		if (this._equipId) {
			json.equipId = this._equipId;
		}
		if (this._configId) {
			json.configId = this._configId;
		}
		if (this._quality) {
			json.quality = this._quality;
		}
		if (this._level) {
			json.level = this._level;
		}
		if (this._streng) {
			json.streng = this._streng;
		}
		if (this._mainAttribute.size() > 0) {
			const ks = this._mainAttribute.getKeys();
			const vs = this._mainAttribute.getValues();
			json.mainAttribute = [ks, vs];
		}
		if (this._randomAttribute.size() > 0) {
			const ks = this._randomAttribute.getKeys();
			const vs = this._randomAttribute.getValues();
			json.randomAttribute = [ks, vs];
		}
		if (this._baseAttribute.size() > 0) {
			const ks = this._baseAttribute.getKeys();
			const vs = this._baseAttribute.getValues();
			json.baseAttribute = [ks, vs];
		}

		return toString ? JSON.stringify(json) : json;
	}


	/**反序列化*/
	public parse(jsonv: string | any): this {
		this.resetProperty();
		if (!jsonv) {
			return this;
		}
		const json = typeof (jsonv) === 'string' ? JSON.parse(jsonv) : jsonv;
		if (json.equipId) {
			this._equipId = json.equipId;
		}
		if (json.configId) {
			this._configId = json.configId;
		}
		if (json.quality) {
			this._quality = json.quality;
		}
		if (json.level) {
			this._level = json.level;
		}
		if (json.streng) {
			this._streng = json.streng;
		}
		if (json.mainAttribute) {
			const ks: number[] = json.mainAttribute[0];
			const vs: number[] = json.mainAttribute[1];
			if (ks && vs && ks.length === vs.length) {	//json
				this._mainAttribute.setKeyAndValueList(ks, vs);
			}
			else if (json.mainAttribute.getKeys && json.mainAttribute.getValues) {	//结构体
				const ks2 = json.mainAttribute.getKeys();
				const vs2 = json.mainAttribute.getValues();
				if (ks2 && vs2 && ks2.length === vs2.length) {
					for (let i = 0, len = vs2.length; i < len; i++) {
						this._mainAttribute.put(ks2[i], vs2[i]);	//重新添加，防止数据公用后被释放导致bug
					}
				}
			}
		}
		if (json.randomAttribute) {
			const ks: number[] = json.randomAttribute[0];
			const vs: number[] = json.randomAttribute[1];
			if (ks && vs && ks.length === vs.length) {	//json
				this._randomAttribute.setKeyAndValueList(ks, vs);
			}
			else if (json.randomAttribute.getKeys && json.randomAttribute.getValues) {	//结构体
				const ks2 = json.randomAttribute.getKeys();
				const vs2 = json.randomAttribute.getValues();
				if (ks2 && vs2 && ks2.length === vs2.length) {
					for (let i = 0, len = vs2.length; i < len; i++) {
						this._randomAttribute.put(ks2[i], vs2[i]);	//重新添加，防止数据公用后被释放导致bug
					}
				}
			}
		}
		if (json.baseAttribute) {
			const ks: number[] = json.baseAttribute[0];
			const vs: number[] = json.baseAttribute[1];
			if (ks && vs && ks.length === vs.length) {	//json
				this._baseAttribute.setKeyAndValueList(ks, vs);
			}
			else if (json.baseAttribute.getKeys && json.baseAttribute.getValues) {	//结构体
				const ks2 = json.baseAttribute.getKeys();
				const vs2 = json.baseAttribute.getValues();
				if (ks2 && vs2 && ks2.length === vs2.length) {
					for (let i = 0, len = vs2.length; i < len; i++) {
						this._baseAttribute.put(ks2[i], vs2[i]);	//重新添加，防止数据公用后被释放导致bug
					}
				}
			}
		}
		return this;
	}


	/**序列化-二进制*/
	public toBytes(byte: Byte): void {
		if (!byte) {
			return;
		}
		byte.writeUint32(this._equipId);
		byte.writeUint32(this._configId);
		byte.writeUint8(this._quality);
		byte.writeUint16(this._level);
		byte.writeUint16(this._streng);
		//主属性
		{
			const ks = this._mainAttribute.getKeys();
			const vs = this._mainAttribute.getValues();
			const len = ks.length;
			byte.writeUint16(len);
			for (let i = 0; i < len; i++) {
				byte.writeUint8(ks[i]);
				byte.writeInt32(vs[i]);
			}
		}
		//随机属性
		{
			const ks = this._randomAttribute.getKeys();
			const vs = this._randomAttribute.getValues();
			const len = ks.length;
			byte.writeUint16(len);
			for (let i = 0; i < len; i++) {
				byte.writeUint8(ks[i]);
				byte.writeInt32(vs[i]);
			}
		}
		//基础属性
		{
			const ks = this._baseAttribute.getKeys();
			const vs = this._baseAttribute.getValues();
			const len = ks.length;
			byte.writeUint16(len);
			for (let i = 0; i < len; i++) {
				byte.writeUint8(ks[i]);
				byte.writeInt32(vs[i]);
			}
		}
	}


	/**反序列化-二进制*/
	public fromBytes(byte: Byte): this {
		this.resetProperty();
		if (!byte) {
			return;
		}
		this._equipId = byte.readUint32();
		this._configId = byte.readUint32();
		this._quality = byte.readUint8();
		this._level = byte.readUint16();
		this._streng = byte.readUint16();
		//主属性
		{
			const len = byte.readUint16();
			for (let i = 0; i < len; i++) {
				const k = byte.readUint8();
				const v = byte.readInt32();
				this._mainAttribute.put(k, v);
			}
		}
		//随机属性
		{
			const len = byte.readUint16();
			for (let i = 0; i < len; i++) {
				const k = byte.readUint8();
				const v = byte.readInt32();
				this._randomAttribute.put(k, v);
			}
		}
		//基础属性
		{
			const len = byte.readUint16();
			for (let i = 0; i < len; i++) {
				const k = byte.readUint8();
				const v = byte.readInt32();
				this._baseAttribute.put(k, v);
			}
		}
		return this;
	}


	/**克隆*/
	public clone(): Equip {
		const byte = Byte.createFromPool();
		this.toBytes(byte);
		byte.pos = 0;
		const clonev = Equip.create().fromBytes(byte);
		Byte.recoverToPool(byte);
		return clonev;
	}


	/**处理更新*/
	public processUpdate(jsonv: string): void {
		if (!jsonv) {
			return;
		}

		const eventID = Equip.EVENT_ID;
		const us = JSON.parse(jsonv);

		for (let i = 0, len = us.length; i < len;) {
			const idx = us[i];
			//装备id
			if (idx === E_Equip.EQUIP_ID) {
				const oldv = this._equipId;
				this._equipId = us[i + 1];
				IAsync.dispatch(eventID, idx, this._equipId, oldv);
				i += 2;
				continue;
			}
			//配置id
			if (idx === E_Equip.CONFIG_ID) {
				const oldv = this._configId;
				this._configId = us[i + 1];
				IAsync.dispatch(eventID, idx, this._configId, oldv);
				i += 2;
				continue;
			}
			//品质
			if (idx === E_Equip.QUALITY) {
				const oldv = this._quality;
				this._quality = us[i + 1];
				IAsync.dispatch(eventID, idx, this._quality, oldv);
				i += 2;
				continue;
			}
			//等级
			if (idx === E_Equip.LEVEL) {
				const oldv = this._level;
				this._level = us[i + 1];
				IAsync.dispatch(eventID, idx, this._level, oldv);
				i += 2;
				continue;
			}
			//强化
			if (idx === E_Equip.STRENG) {
				const oldv = this._streng;
				this._streng = us[i + 1];
				IAsync.dispatch(eventID, idx, this._streng, oldv);
				i += 2;
				continue;
			}

			//主属性
			if (idx === E_Equip.MAIN_ATTRIBUTE) {
				const k: number = us[i + 1];
				const newv :number = us[i + 2];
				const oldv = this.putMainAttribute(k, newv);
				IAsync.dispatch(eventID, idx, k, newv, oldv);
				i += 3;
				continue;
			}

			//随机属性
			if (idx === E_Equip.RANDOM_ATTRIBUTE) {
				const k: number = us[i + 1];
				const newv :number = us[i + 2];
				const oldv = this.putRandomAttribute(k, newv);
				IAsync.dispatch(eventID, idx, k, newv, oldv);
				i += 3;
				continue;
			}

			//基础属性
			if (idx === E_Equip.BASE_ATTRIBUTE) {
				const k: number = us[i + 1];
				const newv :number = us[i + 2];
				const oldv = this.putBaseAttribute(k, newv);
				IAsync.dispatch(eventID, idx, k, newv, oldv);
				i += 3;
				continue;
			}

			console.error('[Struct Data] can not find enum in Equip with idx = ' + idx + ', version maybe wrong.')
		}

		//全更事件
		ITimer.callLater(this, this.dispatchTotalUpdate);
	}


	/**比对不一致结果*/
	public getCompareInfo(other: Equip): string {
		if (!other) {
			return null;
		}

		const updates: any[] = [];

		if (this._equipId !== other._equipId) {
			updates.push(E_Equip.EQUIP_ID, this._equipId);
		}
		if (this._configId !== other._configId) {
			updates.push(E_Equip.CONFIG_ID, this._configId);
		}
		if (this._quality !== other._quality) {
			updates.push(E_Equip.QUALITY, this._quality);
		}
		if (this._level !== other._level) {
			updates.push(E_Equip.LEVEL, this._level);
		}
		if (this._streng !== other._streng) {
			updates.push(E_Equip.STRENG, this._streng);
		}

		//主属性
		{
			const idx = E_Equip.MAIN_ATTRIBUTE;
			const ks1 = this._mainAttribute.getKeys();
			const ks2 = other._mainAttribute.getKeys();
			const vs1 = this._mainAttribute.getValues();
			const vs2 = other._mainAttribute.getValues();
			const rs = MathUtils.intersectSortedArray(ks1, ks2, vs1, vs2);
			if (rs[0].length > 0) {
				const list = rs[0];
				for (let i = 0, len = list.length; i < len; i++) {
					const k = list[i];
					const newv = this.getMainAttribute(k);
					updates.push(idx, k, newv);
				}
			}
			if (rs[1].length > 0) {
				const list = rs[1];
				for (let i = 0, len = list.length; i < len; i++) {
					const k = list[i];
					const newv = this.getMainAttribute(k);
					updates.push(idx, k, newv);
				}
			}
			if (rs[2].length > 0) {
				const list = rs[2];
				for (let i = 0, len = list.length; i < len; i++) {
					updates.push(idx, list[i], 0);
				}
			}
		}

		//随机属性
		{
			const idx = E_Equip.RANDOM_ATTRIBUTE;
			const ks1 = this._randomAttribute.getKeys();
			const ks2 = other._randomAttribute.getKeys();
			const vs1 = this._randomAttribute.getValues();
			const vs2 = other._randomAttribute.getValues();
			const rs = MathUtils.intersectSortedArray(ks1, ks2, vs1, vs2);
			if (rs[0].length > 0) {
				const list = rs[0];
				for (let i = 0, len = list.length; i < len; i++) {
					const k = list[i];
					const newv = this.getRandomAttribute(k);
					updates.push(idx, k, newv);
				}
			}
			if (rs[1].length > 0) {
				const list = rs[1];
				for (let i = 0, len = list.length; i < len; i++) {
					const k = list[i];
					const newv = this.getRandomAttribute(k);
					updates.push(idx, k, newv);
				}
			}
			if (rs[2].length > 0) {
				const list = rs[2];
				for (let i = 0, len = list.length; i < len; i++) {
					updates.push(idx, list[i], 0);
				}
			}
		}

		//基础属性
		{
			const idx = E_Equip.BASE_ATTRIBUTE;
			const ks1 = this._baseAttribute.getKeys();
			const ks2 = other._baseAttribute.getKeys();
			const vs1 = this._baseAttribute.getValues();
			const vs2 = other._baseAttribute.getValues();
			const rs = MathUtils.intersectSortedArray(ks1, ks2, vs1, vs2);
			if (rs[0].length > 0) {
				const list = rs[0];
				for (let i = 0, len = list.length; i < len; i++) {
					const k = list[i];
					const newv = this.getBaseAttribute(k);
					updates.push(idx, k, newv);
				}
			}
			if (rs[1].length > 0) {
				const list = rs[1];
				for (let i = 0, len = list.length; i < len; i++) {
					const k = list[i];
					const newv = this.getBaseAttribute(k);
					updates.push(idx, k, newv);
				}
			}
			if (rs[2].length > 0) {
				const list = rs[2];
				for (let i = 0, len = list.length; i < len; i++) {
					updates.push(idx, list[i], 0);
				}
			}
		}

		const jsonv = updates.length === 0 ? null : JSON.stringify(updates);
		return jsonv;
	}


	/**全部更新*/
	protected dispatchTotalUpdate(): void {
		IAsync.dispatch(Equip.TOTAL_EVENT_ID, this.getV(0));
	}

}
